package com.runchamp.locationUtils;

import android.location.Location;
import android.location.LocationManager;
import android.util.Log;

/**
 * Created by User on 12/3/2014.
 */
public class RunLocationManager {
    public static final double PAUSE_LATITUDE = 100.0;
    public static final double RESUME_LATITUDE = 200.0;
    /**
     * Anything faster than that (in meters per second) will be considered moving.
     */
    public static final double MAX_NO_MOVEMENT_SPEED = 0.224;
    CalorieUtils.ActivityType activityType = CalorieUtils.getActivityType();
    private int recordingDistanceInterval = 1;
    private int maxRecordingDistance = 50;
    private int recordingGpsAccuracy = 50;
    private String TAG = "App";
    private TripStatisticsUpdater tripStatisticsUpdater;
    private long raceID;
    private Track track;
    //ArrayList<Location> locationArray = new ArrayList<Location>();
    // int locationCount = 0;
    //  int currLocation =0;
    //   final int LOCATION_POINTS = 500;
    private Location last;
    private boolean isIdle; // true if idle


    public RunLocationManager() {
        this.tripStatisticsUpdater = new TripStatisticsUpdater(System.currentTimeMillis());
        this.track = new Track();

    }

    public double getSmoothedSpeed() {
        return this.tripStatisticsUpdater.getSmoothedSpeed();
    }


    public TripStatistics getTripStatistics() {
        return this.tripStatisticsUpdater.getTripStatistics();
    }


    /**
     * Inserts a location.
     *
     * @param track               the track
     * @param location            the location
     * @param lastValidTrackPoint the last valid track point, can be null
     */
    private void insertLocation(Track track, Location location, Location lastValidTrackPoint) {


        if (location == null) {
            Log.w(TAG, "Ignore insertLocation. location is null.");
            return;
        }
        // Do not insert if inserted already
        if (lastValidTrackPoint != null && lastValidTrackPoint.getTime() == location.getTime()) {
            Log.w(TAG, "Ignore insertLocation. location time same as last valid track point time.");
            return;
        }

      /*  if(locationCount<LOCATION_POINTS){
            locationArray.add(locationCount,location);
            locationCount++;
            currLocation++;
        }
        else{
            locationArray.add(currLocation,location);
            currLocation = (currLocation+1)%LOCATION_POINTS;
        }*/
        last = location;

        tripStatisticsUpdater.addLocation(location, recordingDistanceInterval, true, activityType, 60);

    }


    /**
     * Called when location changed.
     *
     * @param location the location
     */
    public void onLocationChangedAsync(Location location) {
        try {

            if (track == null) {
                Log.w(TAG, "Ignore onLocationChangedAsync. No track.");
                return;
            }


            if (!LocationUtils.isValidLocation(location)) {
                Log.w(TAG, "Ignore onLocationChangedAsync. location is invalid.");
                return;
            }

            if (!location.hasAccuracy() || location.getAccuracy() >= recordingGpsAccuracy) {
                Log.d(TAG, "Ignore onLocationChangedAsync. Poor accuracy.");
                return;
            }

            // Fix for phones that do not set the time field
            if (location.getTime() == 0L) {
                location.setTime(System.currentTimeMillis());
                Log.d(TAG, "Ignore onLocationChangedAsync. location time 0");

            }

            Location lastValidTrackPoint = last;
            long idleTime = 0L;
            if (lastValidTrackPoint != null && location.getTime() > lastValidTrackPoint.getTime()) {
                idleTime = location.getTime() - lastValidTrackPoint.getTime();
            }


            if (!LocationUtils.isValidLocation(last)) {
        /*
         * Should not happen. The current segment should have a location. Just
         * insert the current location.
         */
                insertLocation(track, location, null);
                last = location;
                Log.d(TAG, "Ignore onLocationChangedAsync. last location null");

                return;
            }

            double distanceToLastTrackLocation = location.distanceTo(lastValidTrackPoint);
            if (distanceToLastTrackLocation > maxRecordingDistance) {
                insertLocation(track, last, lastValidTrackPoint);
                Log.d(TAG, "Ignore onLocationChangedAsync. last location far more then max");

                Location pause = new Location(LocationManager.GPS_PROVIDER);
                pause.setLongitude(0);
                pause.setLatitude(PAUSE_LATITUDE);
                pause.setTime(last.getTime());
                insertLocation(track, pause, null);

                insertLocation(track, location, null);
                isIdle = false;
            } else if (distanceToLastTrackLocation >= recordingDistanceInterval) {
                Log.d(TAG, "Ignore onLocationChangedAsync.distance ok ");

                //insertLocation(track, last, lastValidTrackPoint);
                insertLocation(track, location, lastValidTrackPoint);
                isIdle = false;
            } else if (!isIdle && location.hasSpeed() && location.getSpeed() < MAX_NO_MOVEMENT_SPEED) {
                Log.d(TAG, "Ignore onLocationChangedAsync. speed ok");

                //insertLocation(track, last, lastValidTrackPoint);
                //  insertLocation(track, location, null);
                insertLocation(track, location, lastValidTrackPoint);
                isIdle = true;
            } else if (isIdle && location.hasSpeed() && location.getSpeed() >= MAX_NO_MOVEMENT_SPEED) {
                Log.d(TAG, "Ignore onLocationChangedAsync. speed more then max");

                //  insertLocation(track, last, lastValidTrackPoint);
                //insertLocation(track, location, null);
                insertLocation(track, location, lastValidTrackPoint);
                isIdle = false;
            } else {
                Log.d(TAG, "Not recording location, idle");
                insertLocation(track, location, lastValidTrackPoint);

            }
            last = location;

        } catch (Error e) {
            Log.e(TAG, "Error in onLocationChangedAsync", e);
            throw e;
        } catch (RuntimeException e) {
            Log.e(TAG, "RuntimeException in onLocationChangedAsync", e);
            throw e;
        }
    }
}
